package com.aisile.crowd_funding.common.aspect;

import com.aisile.crowd_funding.common.annotion.Log;
import com.aisile.crowd_funding.common.utils.ShiroUtils;
import com.aisile.crowd_funding.system.pojo.SysLog;
import com.aisile.crowd_funding.system.pojo.SysUser;
import com.aisile.crowd_funding.system.service.LogService;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;

/**
 * 日志切面类
 */
@Aspect//注解当前类为切面类
@Component//必须加上这个才能被spring 管理
public class LogAspect {

    @Autowired
    LogService logService;
    //pointcut 注解是表明哪些方法要被切面处理这里我们定义好了一个注解意思就是凡是被这个注解标注的方法被切面处理
    @Pointcut("@annotation(com.aisile.crowd_funding.common.annotion.Log)")
    public void Pointcut(){

    }

    //前置通知
    @Before("Pointcut()")
    public void beforeHandler(){
        System.out.println("前置通知被触发了");
    }
    @After("Pointcut()")
    public void after(){
        System.out.println("后置通知被触发了");
    }

    @Around("Pointcut()")
    public Object Around(ProceedingJoinPoint point) throws  Throwable{
        Object proceed=null;

        try {
            SysLog log=new SysLog();
            log.setGmtCreate(new Date());
            //在这写就是前置通知
            //获取当前毫秒
            Long startTime=System.currentTimeMillis();
            //可以把它看成获取到的方法proceed是一个最大的类操作完成之后return
            proceed=point.proceed();
            //获取当前毫秒
            Long endTime=System.currentTimeMillis();
            //算出方法的执行时间
            log.setTime((int)(endTime-startTime));
            System.out.print(endTime-startTime);
            //获取当前操作用户因为是用的shiro所以能通过seccurity得到它

            SysUser sysUser= ShiroUtils.getSubject();
            log.setUserId(sysUser.getUserId());
            log.setUsername(sysUser.getUsername());
            //利用反射获取注解从而知道当前是一个什么操作
            MethodSignature methodSignature=(MethodSignature)point.getSignature();
            Method method = methodSignature.getMethod();
            //利用反射获取方法上的注解
            Log annotation = method.getAnnotation(Log.class);
            //得到注解里的值
            String opertioan=annotation.value();
            //获取方法名称
            log.setOperation(opertioan);

            log.setMethod(method.getName());
            //获取方法所在类
            method.getDeclaringClass().toString();
            //获取ip这个就可以知道哪一台电脑操作的
            //得到request Ip需要request对象获取
            HttpServletRequest request=((ServletRequestAttributes)  RequestContextHolder.getRequestAttributes()).getRequest();
           //获取本地Ip
            request.getLocalAddr();
            //获取远程Ip

             log.setIp(request.getRemoteAddr());
            //在这写就是后置通知
            logService.insert(log);


        }catch (Exception e){
            //在这写就是异常通知
        }finally {
           //在这写就是最终通知
        }

        return proceed;
    }
}
